#ifndef CPPJIEBA_QUERYSEGMENT_H
#define CPPJIEBA_QUERYSEGMENT_H

#include <algorithm>
#include <set>
#include <cassert>
#include "limonp/Logging.hpp"
#include "DictTrie.hpp"
#include "SegmentBase.hpp"
#include "FullSegment.hpp"
#include "MixSegment.hpp"
#include "Unicode.hpp"

namespace cppjieba
{
  class QuerySegment : public SegmentBase
  {
  public:
    QuerySegment(const string &dict, const string &model, const string &userDict = "")
        : mixSeg_(dict, model, userDict),
          trie_(mixSeg_.GetDictTrie())
    {
    }
    QuerySegment(const DictTrie *dictTrie, const HMMModel *model)
        : mixSeg_(dictTrie, model), trie_(dictTrie)
    {
    }
    ~QuerySegment()
    {
    }

    void Cut(const string &sentence, vector<string> &words) const
    {
      Cut(sentence, words, true);
    }
    void Cut(const string &sentence, vector<string> &words, bool hmm) const
    {
      vector<Word> tmp;
      Cut(sentence, tmp, hmm);
      GetStringsFromWords(tmp, words);
    }
    void Cut(const string &sentence, vector<Word> &words, bool hmm = true) const
    {
      PreFilter pre_filter(symbols_, sentence);
      PreFilter::Range range;
      vector<WordRange> wrs;
      wrs.reserve(sentence.size() / 2);
      while (pre_filter.HasNext())
      {
        range = pre_filter.Next();
        Cut(range.begin, range.end, wrs, hmm);
      }
      words.clear();
      words.reserve(wrs.size());
      GetWordsFromWordRanges(sentence, wrs, words);
    }
    void Cut(RuneStrArray::const_iterator begin, RuneStrArray::const_iterator end, vector<WordRange> &res, bool hmm) const
    {
      // use mix Cut first
      vector<WordRange> mixRes;
      mixSeg_.Cut(begin, end, mixRes, hmm);

      vector<WordRange> fullRes;
      for (vector<WordRange>::const_iterator mixResItr = mixRes.begin(); mixResItr != mixRes.end(); mixResItr++)
      {
        if (mixResItr->Length() > 2)
        {
          for (size_t i = 0; i + 1 < mixResItr->Length(); i++)
          {
            WordRange wr(mixResItr->left + i, mixResItr->left + i + 1);
            if (trie_->Find(wr.left, wr.right + 1) != NULL)
            {
              res.push_back(wr);
            }
          }
        }
        if (mixResItr->Length() > 3)
        {
          for (size_t i = 0; i + 2 < mixResItr->Length(); i++)
          {
            WordRange wr(mixResItr->left + i, mixResItr->left + i + 2);
            if (trie_->Find(wr.left, wr.right + 1) != NULL)
            {
              res.push_back(wr);
            }
          }
        }
        res.push_back(*mixResItr);
      }
    }

  private:
    bool IsAllAscii(const Unicode &s) const
    {
      for (size_t i = 0; i < s.size(); i++)
      {
        if (s[i] >= 0x80)
        {
          return false;
        }
      }
      return true;
    }
    MixSegment mixSeg_;
    const DictTrie *trie_;
  }; // QuerySegment

} // namespace cppjieba

#endif
